using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;

namespace Abide_AddOn_API.Meta
{
	public class HaloPlugin
	{
		public HaloMetaObject MainObject;
		public string FileName;
		public List<HaloMetaObject> Revisions;
		public List<HaloPlugin.PluginErrorType> PluginErrors;
		private XmlDocument PluginDocument;
		public HaloPlugin()
		{
			this.MainObject = new HaloMetaObject();
			this.MainObject.ChildObjects = new List<HaloMetaObject>();
			this.PluginErrors = new List<HaloPlugin.PluginErrorType>();
		}
		public HaloPlugin(string PluginFileName) : this()
		{
			this.FileName = PluginFileName;
		}
		public bool Load(string PluginFileName)
		{
			this.FileName = PluginFileName;
			return this.Load();
		}
		public bool Load()
		{
			if (!File.Exists(this.FileName))
			{
				return false;
			}
			this.Revisions = new List<HaloMetaObject>();
			this.PluginDocument = new XmlDocument();
			this.PluginDocument.Load(this.FileName);
			this.MainObject.Class = this.GetAttribute(this.PluginDocument["plugin"], "class");
			this.MainObject.Author = this.GetAttribute(this.PluginDocument["plugin"], "author");
			this.MainObject.Version = this.GetAttribute(this.PluginDocument["plugin"], "version");
			this.MainObject.Size = this.GetAttribute(this.PluginDocument["plugin"], "headersize");
			if (this.MainObject.Class == "null")
			{
				this.MainObject.Class = this.GetAttribute(this.PluginDocument["plugin"], "name");
				this.MainObject.Size = this.GetAttribute(this.PluginDocument["plugin"], "size");
			}
			this.MainObject.ChildObjects.AddRange(this.LoadChildNode(this.PluginDocument["plugin"]));
			return true;
		}
		private List<HaloMetaObject> LoadChildNode(XmlNode ParentNode)
		{
			List<HaloMetaObject> list = new List<HaloMetaObject>();
			foreach (XmlNode xmlNode in ParentNode.ChildNodes)
			{
				HaloMetaObject haloMetaObject = new HaloMetaObject();
				haloMetaObject.Type = xmlNode.Name.ToLower();
				haloMetaObject.Name = this.GetAttribute(xmlNode, "name");
				haloMetaObject.Offset = this.GetAttribute(xmlNode, "offset");
				haloMetaObject.Visible = this.GetAttribute(xmlNode, "visible");
				haloMetaObject.Size = this.GetAttribute(xmlNode, "size");
				haloMetaObject.Label = this.GetAttribute(xmlNode, "label");
                haloMetaObject.MaxElements = this.GetAttribute(xmlNode, "maxelements");
                haloMetaObject.PadAlign = this.GetAttribute(xmlNode, "padalign");
				haloMetaObject.Value = this.GetAttribute(xmlNode, "value");
				haloMetaObject.ReflexiveOffset = this.GetAttribute(xmlNode, "reflexiveoffset");
				haloMetaObject.ReflexiveSize = this.GetAttribute(xmlNode, "reflexivesize");
				haloMetaObject.ItemOffset = this.GetAttribute(xmlNode, "itemoffset");
				haloMetaObject.ItemType = this.GetAttribute(xmlNode, "itemtype");
				haloMetaObject.Layer = this.GetAttribute(xmlNode, "layer");
				haloMetaObject.TagTypeOffset = this.GetAttribute(xmlNode, "tagtypeoffset");
				haloMetaObject.IdentOffset = this.GetAttribute(xmlNode, "identoffset");
				haloMetaObject.VirtualOffset = this.GetAttribute(xmlNode, "virtoffset");
				string type;
				if ((type = haloMetaObject.Type) != null && type == "revision")
				{
					haloMetaObject.Author = this.GetAttribute(xmlNode, "author");
					haloMetaObject.Version = this.GetAttribute(xmlNode, "version");
					haloMetaObject.Description = xmlNode.InnerText;
					Revisions.Add(haloMetaObject);
				}
				else
					list.Add(haloMetaObject);

				if (xmlNode.ChildNodes.Count > 0)
					haloMetaObject.ChildObjects.AddRange(this.LoadChildNode(xmlNode));
			}
			return list;
		}
		public string GetAttribute(XmlNode Node, string AttributeName)
		{
			string result = string.Empty;
			if (Node != null && Node.Attributes != null && Node.Attributes[AttributeName] != null)
				result = Node.Attributes[AttributeName].Value;

            return string.IsNullOrEmpty(result) ? "null" : result;
		}
        public HaloMetaObject[] this[string ChildName]
        {
            get
            {
                return MainObject.ChildObjects.FindAll(c => c.Name == ChildName).ToArray();
            }
        }

        public enum PluginErrorType
        {
            MissingAttribute,
            EmptyAttribute,
            SameValueEntry
        }
	}
}
